<template>
	<view class="chat-container" id="chat-scroll">
		<!-- 聊天消息区 -->
		<view class="msg-list">
			<view class="msg" v-for="(msg, index) in chatMessages" :key="index"
				:class="msg.role === 'user' ? 'msg-user' : 'msg-ai'">
				<rich-text class="msg-content" :nodes="formatToRichText(msg.content)" />
			</view>

			<view class="ai-loading" v-if="loading">
				<text style="margin-right: 10rpx;">AI 正在输入</text>
				<view class="dot-flash">
					<view class="dot" v-for="i in 3" :key="i" :style="{ animationDelay: (i * 0.2) + 's' }"></view>
				</view>
			</view>
		</view>

		<!-- 底部输入框 -->
		<view class="input-bar" :class="hasChat ? 'input-bottom' : 'input-center'">
			<view class="input-wrapper">
				<u-input :adjustPosition='false' v-model="userInput" placeholder="请输入问题..." shape="circle" border="surround" :clearable="true"
					class="input-box" @confirm="handleSend" />
				<u-button type="primary" size="medium" class="send-btn" shape="circle" @click="handleSend">
					发送
				</u-button>
			</view>
		</view>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				chatMessages: [],
				userInput: '',
				isSocketOpen: false,
				loading: false,
			};
		},
		computed: {
			hasChat() {
				return this.chatMessages.length > 0;
			}
		},
		onLoad() {
			this.initSocket();
		},
		methods: {
			// 格式化文档
			formatToRichText(text) {
				return text.split(/\n/).map(paragraph => ({
					name: 'p',
					attrs: {
						style: 'margin-bottom: 20rpx; line-height: 1.9; white-space: normal; word-break: break-word;'
					},
					children: [{
						type: 'text',
						text: paragraph
					}]
				}));
			},
			initSocket() {
				uni.connectSocket({
					url: 'ws://47.120.60.61:9876/chat-ws',
					success: () => console.log("WebSocket 请求已发送"),
					fail: (err) => console.error("连接失败", err)
				});

				uni.onSocketOpen(() => {
					console.log("WebSocket 连接已打开");
					this.isSocketOpen = true;
				});

				uni.onSocketMessage((res) => {
					if (res.data === "[DONE]") {
						this.loading = false;
						return;
					}
					this.appendCharByChar(res.data);
				});

				uni.onSocketClose(() => {
					console.log("WebSocket 已关闭");
					this.isSocketOpen = false;
				});

				uni.onSocketError((err) => {
					console.error("WebSocket 错误", err);
				});
			},

			handleSend() {
				console.log('发送消息' + this.userInput.trim())
				const msg = this.userInput.trim();
				if (!msg || !this.isSocketOpen) return;

				this.chatMessages.push({
					role: 'user',
					content: msg
				});
				this.scrollToBottom();
				this.userInput = '';
				this.loading = true;
				this.sendUserMessageWithContext();
			},

			sendUserMessageWithContext() {
				const context = this.chatMessages.map(msg => {
					return (msg.role === 'user' ? "用户：" : "AI：") + msg.content;
				}).join('\n');

				uni.sendSocketMessage({
					data: context,
					success: () => console.log("上下文发送成功"),
					fail: (err) => {
						console.error("发送失败", err);
						this.loading = false;
					}
				});
			},

			appendCharByChar(text) {
				let lastMsg = this.chatMessages[this.chatMessages.length - 1];
				if (!lastMsg || lastMsg.role !== 'ai') {
					lastMsg = {
						role: 'ai',
						content: ''
					};
					this.chatMessages.push(lastMsg);
				}

				// 直接拼接，不使用字符延时动画
				lastMsg.content += text;
				this.$forceUpdate();
				this.scrollToBottom();
			},

			scrollToBottom() {
				this.$nextTick(() => {
					uni.pageScrollTo({
						scrollTop: 99999,
						duration: 100
					});
				});
			}
		}
	};
</script>

<style>
	/* 悬浮导航栏样式 */
	.navbar-fixed {
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		z-index: 999;
		background-color: #fff;
		/* 或你需要的背景色 */
	}

	.chat-container {
		background-color: #f5f5f5;
		padding-bottom: 180rpx;
		min-height: 100vh;
		display: flex;
		flex-direction: column;
		justify-content: space-between;
	}


	.msg-list {
		padding: 20rpx;
		padding-top: 100rpx;
		flex: 1;
		overflow-y: auto;
	}

	.msg {
		max-width: 80%;
		margin: 20rpx 0;
		padding: 24rpx;
		border-radius: 20rpx;
		word-break: break-word;
		font-size: 28rpx;
		line-height: 1.6;
	}

	.msg-user {
		background-color: #4a90e2;
		color: white;
		align-self: flex-end;
		margin-left: auto;
		border-bottom-right-radius: 0;
	}

	.msg-ai {
		background-color: #ffffff;
		color: #333;
		align-self: flex-start;
		margin-right: auto;
		border-bottom-left-radius: 0;
		box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
	}

	.ai-loading {
		display: flex;
		align-items: center;
		font-size: 28rpx;
		margin: 20rpx;
		color: #888;
	}

	.input-bar {
		display: flex;
		align-items: center;
		padding: 20rpx;
		background-color: #fff;
		box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
		position: fixed;
		bottom: 0;
		width: 100%;
		z-index: 99;
		height: 150rpx;
	}

	.input-box {
		flex: 1;
		margin-right: 30rpx;
		margin-left: 30rpx;
		border-radius: 30rpx;
		width: 80%;
	}

	.send-btn {
		width: 160rpx;
	}

	/* --- */
	.msg-content {
		color: #333;
		font-size: 28rpx;
		line-height: 1.9;
		white-space: pre-wrap;
		word-break: break-word;
		word-wrap: break-word;
	}

	.dot-flash {
		display: flex;
		margin-left: 10rpx;
	}

	.dot {
		width: 12rpx;
		height: 12rpx;
		background-color: #4a90e2;
		border-radius: 50%;
		margin-left: 8rpx;
		animation: flashDot 1.2s infinite;
	}

	@keyframes flashDot {
		0% {
			opacity: 0.2;
			transform: scale(0.8);
		}

		50% {
			opacity: 1;
			transform: scale(1.2);
		}

		100% {
			opacity: 0.2;
			transform: scale(0.8);
		}
	}

	.input-wrapper {
		display: flex;
		width: 100%;
		padding-right: 30px;
	}
</style>